﻿#region copyright
//<copyright>
// Copyright(C) 2012 TrackerRealm Corporation
// This file is part of the open source project - Jazz. http://jazz.codeplex.com
// 
// Jazzfire is open software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License (AGPL) as published by the Free Software Foundation, version 3 of the License.
// 
// Jazzfire is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License (AGPL) for more details.
// 
// You should have received a copy of the GNU General Public License along with Jetfire.  If not, see <http://www.gnu.org/licenses/>.
//
// REMOVAL OF THIS NOTICE IS VIOLATION OF THE COPYRIGHT. 
//</copyright>
#endregion
# region using
using System;
using System.Linq;
using System.Collections.Generic;
using TrackerRealm.Jazz.Client;
using TrackerRealm.Jazz.Client.Custom;
# endregion

namespace TrackerRealm.Jazz.WindowsForm
{
    /// <summary>
    /// ToDoItemExample implements a simple to do item.
    /// </summary>
    [Jazz]
    public partial class ToDoItemExample : jObject
    {
        # region Constructor and initialization
        /// <summary>
        /// Factory method to create a ToDoItemExample
        /// </summary>
        /// <returns></returns>
        public static ToDoItemExample CreateEmpty()
        {
            return new ToDoItemExample();
        }
        /// <summary>
        /// Factory method to Create a To Do Item
        /// </summary>
        /// <param name="nexus">Nexus</param>
        /// <param name="subject">Subject of To Do Item</param>
        /// <returns></returns>
        public static ToDoItemExample Create(ClientNexus nexus, string subject)
        {
            ToDoItemExample item = new ToDoItemExample(nexus);
            item.Subject = subject;
            return item;
        }
        # region Assign Fixed Ids.
        /// <summary>
        /// The ID for the 'Empty' ToDoItemExample.
        /// </summary>
        public static readonly Guid EmptyID = new Guid("E0263939-C7B4-4D23-89AA-7F75B8B309FE");
        /// <summary>
        /// Assigns a fixed ID to the 'Empty' to do item.
        /// </summary>
        /// <returns></returns>
        protected override Guid OnAssignID()
        {
            if (this.IsEmpty)
                return ToDoItemExample.EmptyID;
            return base.OnAssignID();
        }
        # endregion
        /// <summary>
        /// Private constructor 
        /// </summary>
        /// <param name="nexus"></param>
        private ToDoItemExample(ClientNexus nexus) : base(null)
        {
            this.Initialize();
            this.MoveItem(nexus);
            nexus.Bind(this);
        }
        private void MoveItem(ClientNexus nexus)
        {
            if (nexus == null)
                return;
            // Move item to To Do Workspace
            jWorkspace ws = nexus.Cache.OfType<jWorkspace>().SingleOrDefault(s => s.Name == "To Do Workspace");
            if (ws != null)
                ws.Move(this);
        }
        /// <summary>
        /// Private default Constructor
        /// </summary>
        private ToDoItemExample() : base()
        {
            this.Initialize();
        }
        /// <summary>
        /// Initialize parameters at instantiation
        /// </summary>
        void Initialize()
        {
            this.Subject = "To Do Item";
            this.SetTimePeriod();
        }
        /// <summary>
        /// When the jObject is first bound to the Nexus
        /// </summary>
        protected override void OnInitialBind()
        {
            base.OnInitialBind();
            if (this.IsEmpty)
                this.Subject = " No To Do Item";
        }
        # endregion
        # region Properties
        /// <summary>
        /// Gets the Client Nexus (removes need for casting in code using this class)
        /// </summary>
        [SerializeIgnore]
        public new ClientNexus ClientNexus
        {
            get { return (ClientNexus) base.ClientNexus; }
        }
        /// <summary>
        /// Gets and Sets the Subject.  
        /// The Subject may only be set when the state is 'Started' and this To Do Item 'IsValid'
        /// </summary>
        [UI]
        public string Subject
        {
            get;
            [GrantStates("Started"), GrantProperty("IsValid")]
            set;
        }
        /// <summary>
        /// Gets and Sets the Description
        /// The Description may only be set when the state is 'Started' and this To Do Item 'IsValid'
        /// </summary>
        [UI]
        public string Description
        {
            get;
            [GrantStates("Started"), GrantProperty("IsValid")]
            set;
        }
        /// <summary>
        /// Gets and Sets a Manager Comment
        /// The Subject may only be set when the state is 'Started' or 'Finished' by the 'Manager' Role and this To Do Item 'IsValid'
        /// </summary>
        [UI]
        public string Manager_Comment
        {
            get;
            [GrantStates("Started","Finished"), GrantRoles("Manager"), GrantProperty("IsValid")]
            set;
        }
        /// <summary>
        /// Gets and Sets the Start Date and Time
        /// The Start may only be set when the state is 'Started' and this To Do Item 'IsValid'
        /// </summary>
        [UI]
        public DateTime Start
        {
            get;
            [GrantStates("Started"), GrantProperty("IsValid")]
            set;
        }
        /// <summary>
        /// Gets and Sets the End Date and Time
        /// The End may only be set when the state is 'Started' and this To Do Item 'IsValid'
        /// </summary>
        [UI]
        public DateTime End
        {
            get;
            [GrantStates("Started"), GrantProperty("IsValid")]
            set;
        }
        # endregion
        # region State Methods
        /// <summary>
        /// The To Do Item (automatically) starts in the 'Started' state
        /// </summary>
        [StartState]
        void Started()   { }
        /// <summary>
        /// If the To Do Item is no longer required, it is promoted into the 'Cancelled' state
        /// </summary>
        [FinalState]
        void Cancelled() 
        {
            // Delete the item - does not need to be tracked
            this._Delete();
        }
        /// <summary>
        /// Once the To Do Item is done, the user promotes it into the 'Finished' state
        /// </summary>
        [State]
        void Finished()  { }
        /// <summary>
        /// When the To Do Item is accepted by the 'Manager', it enters the 'Completed' state
        /// </summary>
        [FinalState]
        void Completed() { }
        # endregion
        # region C O M M A N D S
        /// <summary>
        /// Initialization set the Time Period to default values
        /// </summary>
        private void SetTimePeriod()
        {
            DateTime today = DateTime.Today.AddHours(8);
            this.Start = today;
            TimeSpan too = TimeSpan.FromHours(8);
            this.End = today.Add(too);
        }
        /// <summary>
        /// If the ACL has no members, then this To Do Item is public in the workspace
        /// </summary>
        bool IsPublic
        {
            get
            {
                if (this.IsValid)
                    return this._ACL.Count() == 0;
                return false;
            }
        }
        /// <summary>
        /// If the ACL has members, then this To Do Item has been assigned to someone
        /// </summary>
        bool IsAssigned
        {
            get
            {
                if (this.IsValid)
                    return this._ACL.Count() > 0;
                return false;
            }
        }
        /// <summary>
        /// Assign this To Do Item to the Logged in user, the 'Manager' Role and users with the 'ToDo' role
        /// </summary>
        [UI, GrantStates("Started"), GrantProperty("IsPublic")]
        public void Assign()
        {
            foreach (jAclItem aclItem in this._ACL)
            {
                if (aclItem.Role == this.ClientNexus.LoginProfile)
                    return;
            }
            this._Add(jAclItem.Accessible(this.ClientNexus.LoginProfile));
            jRole role = this.ClientNexus.Cache.OfType<jRole>().Single(r => r.Name == "Manager");
            this._Add(jAclItem.Accessible(role));
            role = this.ClientNexus.Cache.OfType<jRole>().Single(r => r.Name == "ToDo");
            this._Add(jAclItem.ReadOnly(role));
        }
        /// <summary>
        /// Clear the Access Control List for the To Do Item
        /// </summary>
        [UI, GrantStates("Started"), GrantProperty("IsAssigned")]
        public void Unassign()
        {
            for (int i = this._ACL.Count() - 1; i >= 0; i--)
            {
                jAclItem aclItem = this._ACL.ElementAt(i);
                this._Remove(aclItem);
            }
        }
        /// <summary>
        /// Checks if this To Do Item has an ACL where the Logged in user is in the ACL or the ACL has Roles
        /// </summary>
        bool IsMyItem
        {
            get
            {
                if (!this.IsValid)
                    return false;
                return this.ACL.Count(r => r.Role == this.ClientNexus.LoginProfile || this.ClientNexus.LoginRoles.Contains(r.Role)) > 0;
            }
        }
        /// <summary>
        /// The Cancel command can be used in the Started states by the 'owner' of the To Do Item
        /// </summary>
        [UI, GrantStates("Started"), GrantProperty("IsMyItem")]
        public void Cancel()
        {
            this.EnterState("Cancelled");
        }
        /// <summary>
        /// The Complete command can be used in the Started states by the 'owner' of the To Do Item
        /// </summary>
        [UI, GrantStates("Started"), GrantProperty("IsMyItem")]
        public void Finish()
        {
            this.EnterState("Finished");
        }
        /// <summary>
        /// The 'Manager' 'Accepts' the To Do Item in the 'Finished' state
        /// </summary>
        [UI, GrantStates("Finished"), GrantRoles("Manager")]
        public void Accept()
        {
            this.EnterState("Completed");
        }
        /// <summary>
        /// The 'Manager' 'Rejects' the To Do Item in the 'Finished' state
        /// </summary>
        [UI, GrantStates("Finished"), GrantRoles("Manager")]
        public void Reject()
        {
            this.EnterState("Started");
        }
        /// <summary>
        /// Delete this To Do Item
        /// </summary>
        /// <returns></returns>
        [UI, GrantStates("Started"), GrantProperty("IsMyItem")]
        public bool Delete()
        {
            this._Delete();
            return this.IsDeleted;
        }
        # endregion
        # region ACL
        /// <summary>
        /// This To Do Item can be written to
        /// </summary>
        bool IsWritable
        {
            get { return this.IsValid && !this.IsReadOnly; }
        }
        /// <summary>
        /// The ACL (Access Control List) controls how this '<see cref="jObject"/>' instance
        /// can be accessed.
        /// <para>Note: If the ACL sequence is empty, then there are no access restrictions.</para>
        /// </summary>
        [GrantProperty("IsWritable")]
        public IEnumerable<jAclItem> ACL
        {
            get { return base._ACL; }
        }
        # endregion
    }
}